/** 
 * FunctionExpression.java
 * @author Lex
 * 2007-8-20 ����06:15:21
 */
package fun.parser.ast.node;

import fun.parser.EvaluationException;
import fun.parser.FunctionNotFoundException;
import fun.parser.ast.node.base.Expression;
import fun.parser.lexer.Token;
import fun.symtable.FixsizeSymbolTable;
import fun.symtable.FunctionEntry;
import fun.symtable.SymbolTable;
import fun.symtable.VariableEntry;

public class FunctionExpression extends Expression {
    protected Expression[] argumentExpressions = new Expression[0];

    public FunctionExpression(Token node, Expression[] args) {
	super(node);
	if (null == args)
	    args = new Expression[0];
	this.argumentExpressions = args;
	this.setChildren(args);
    }

    public Expression[] getArguments() {
	return this.argumentExpressions;
    }

    public String getFunctionName() {
	return this.getToken().getImage();
    }

    @Override
    public double getValue(SymbolTable symtable) throws EvaluationException {
	// ���Һ������
	String name = getFunctionName();
	FunctionEntry functionEntry = symtable.getFunction(name, argumentExpressions.length);
	// ================================================
	// ��Ϊ������"�������",����û���ڷ�ű����ҵ��ú����׳��쳣
	if (null == functionEntry)
	    throw new FunctionNotFoundException(this);
	// ==============================================
	// �����β�-ʵ�η�ű�
	// ��ʱ functionEntry ��Ϊ null����ʼΪ�������ű?���ҽ��β���ӵ���ű���
	String[] argNames = functionEntry.getParameters();
	SymbolTable functionSymbolTable = new FixsizeSymbolTable(functionEntry.toString(), 0, argNames.length);
	functionSymbolTable.setParent(symtable);
	// ========================================
	// ����βε���ű�
	VariableEntry[] argumentEntries = new VariableEntry[argNames.length];
	for (int i = 0; i < argNames.length; i++)
	    argumentEntries[i] = functionSymbolTable.setVariable(argNames[i], 0);
	// =====================
	// ��ʵ����ֵ��Ȼ��ֵ���β�
	for (int i = 0; i < argumentEntries.length; i++)
	    argumentEntries[i].setValue(argumentExpressions[i].getValue(symtable));
	// ���㺯��ֵ
	Expression expr = functionEntry.getExpression();
	return expr.getValue(functionSymbolTable);
    }

    public String toPlainString() {
	StringBuilder b = new StringBuilder();
	b.append(this.getToken().getImage()).append('(');
	int comma = argumentExpressions.length - 1;
	for (int i = 0; i < argumentExpressions.length; i++) {
	    b.append(argumentExpressions[i].toString());
	    if (i < comma)
		b.append(',').append(' ');
	}
	b.append(')');
	return b.toString();
    }
}
